import XmlTkinter.Base as Base
import os
import pickle
import gzip
import webbrowser
import datetime

## represent bookmarks value model
class BookmarksModel(Base.BaseModel):
    def __init__(self):
        Base.BaseModel.__init__(self)
        self.data      = None
        self.bookmarks = None
        self.options   = None
        self.filter    = []
        self.current   = None
        self.display   = "bkm_choose_url"
        self.backup    = "bkm_backup_none"

    ## this is required to register the model for a concrete GUI element
    #  and all sub elements.
    def id(self):
        return "master"

    def rebuildList(self):
        self.clear("bkm_list")
        self.filter = []
        self.searchBookmark(self.getValue("bkm_search"))

        self.select("bkm_list", 0)

    ## trying to load saved bookmarks
    def initialize(self):
        # checking for saved bookmarks
        if os.path.isfile("bookmarks.gz"):
            self.data = pickle.load(gzip.open("bookmarks.gz"))

            #file = open('bookmarks.cfg', 'rb')
            #self.data = pickle.load(file)
            #file.close()

            # more senseful access to individual data
            self.bookmarks = self.data["bookmarks"]
            self.options   = self.data["options"]

            self.setValue("bkm_incremental_search" , self.options["incremental"        ])
            self.setValue("bkm_ignorecase"         , self.options["ignorecase"         ])
            self.setValue("bkm_search_names"       , self.options["search_names"       ])
            self.setValue("bkm_search_urls"        , self.options["search_urls"        ])
            self.setValue("bkm_search_tags"        , self.options["search_tags"        ])
            self.setValue("bkm_search_descriptions", self.options["search_descriptions"])
            self.setValue("bkm_search"             , self.options["search"             ])

            self.display = self.options["display"]
            self.setValue(self.display)

            self.backup = self.options["backup"]
            self.setValue(self.backup)

            self.rebuildList()
            # displaying details for first (selected) row...
            value = self.getValue("bkm_list", 0)
            self.updateValue("bkm_list", value, "changed")

        # displaying number of bookmarks in the statusbar.
        message = self.getText("#bkm_number") % (len(self.bookmarks))
        self.setValue("bkm_statusbar", message)

    ## checking whether give name does not exist!
    def isUniqueName(self, name):
        for bookmark in self.bookmarks.values():
            if bookmark["name"] == name:
                return False
        return True

    ## checking whether give url does not exist!
    def isUniqueURL(self, url):
        return not self.bookmarks.has_key(url)

    ## checking whether give url or name does exist!
    def hasUrlOrName(self, value):
        if self.display == "bkm_choose_name":
            for bookmark in self.bookmarks.values():
                if bookmark["name"] == value:
                    return True
            return False
        else:
            return self.bookmarks.has_key(value)

    def getUrlOrName(self, value):
        if self.display == "bkm_choose_name":
            for bookmark in self.bookmarks.values():
                if bookmark["name"] == value:
                    return bookmark
            return None
        else:
            try:
                return self.bookmarks[value]
            except:
                return None

    ## trying to add a new bookmark using current input
    def addBookmark(self):
        # current input
        name        = self.getValue("bkm_name")
        url         = self.getValue("bkm_url")
        description = self.getValue("bkm_description")
        tag         = self.getValue("bkm_tag")

        # checking for validity
        if len(name.strip()) == 0 or len(url.strip()) == 0:
            print self.getText("#bkm_can_not_add_empty_entries") % (url)
            return

        if not self.isUniqueName(name):
            print self.getText("#bkm_can_not_add_name_still_present") % (url)
            return

        if not self.isUniqueName(url):
            print self.getText("#bkm_can_not_add_url_still_present") % (url)
            return

        # creating new bookmark
        bookmark                = {}
        bookmark["name"       ] = name
        bookmark["url"        ] = url
        bookmark["description"] = description
        bookmark["tag"        ] = tag
        bookmark["created"    ] = str(datetime.datetime.now()).split(" ")
        bookmark["changed"    ] = bookmark["created"]

        # adding bookmark
        self.bookmarks[url] = bookmark

        if self.display == "bkm_choose_url":
            self.addValue("bkm_list", url)
        else:
            self.addValue("bkm_list", name)

        self.setAttribute("bkm_name", "state", "disabled")
        self.setAttribute("bkm_url" , "state", "disabled")
        self.setAttribute("bkm_add" , "state", "disabled")

        # displaying number of bookmarks in the statusbar.
        message = self.getText("#bkm_number") % (len(self.bookmarks))
        self.setValue("bkm_statusbar", message)

    ## reset of input to allow adding new bookmark
    def newBookmark(self):
        self.setAttribute("bkm_name"  , "state", "normal")
        self.setAttribute("bkm_url"   , "state", "normal")
        self.setAttribute("bkm_add"   , "state", "normal")
        self.setAttribute("bkm_change", "state", "disabled")
        self.setAttribute("bkm_delete", "state", "disabled")

        self.setValue("bkm_name"       , "")
        self.setValue("bkm_url"        , "")
        self.setValue("bkm_description", "")
        self.setValue("bkm_tag"        , "")

    ## trying to change given bookmark (input)
    def changeBookmark(self):
        description = self.getValue("bkm_description")
        tag         = self.getValue("bkm_tag")

        self.current["description"] = description
        self.current["tag"]         = tag
        self.current["changed"]     = str(datetime.datetime.now()).split(" ")

    ## trying to delete given bookmark (input)
    def deleteBookmark(self):
        entry = self.getValue("bkm_url")
        if self.display == "bkm_choose_name":
            entry = self.getValue("bkm_name")

        self.removeValue("bkm_list", entry)
        self.updateValue("bkm_list", entry, "deleted")

    ## search for a bookmark (filtering)
    def searchBookmark(self, value):
        ignoreCase           = "on" == self.getValue("bkm_ignorecase")
        searchInUrls         = "on" == self.getValue("bkm_search_urls")
        searchInNames        = "on" == self.getValue("bkm_search_names")
        searchInTags         = "on" == self.getValue("bkm_search_tags")
        searchInDescriptions = "on" == self.getValue("bkm_search_descriptions")

        for url in self.bookmarks.keys():
            bookmark = self.bookmarks[url]
            valid    = False

            if len(value) == 0:
                valid = True

            if not valid and searchInUrls:
                if url.find(value) >= 0 or \
                   (ignoreCase and url.lower().find(value.lower()) >= 0):
                    valid = True

            if not valid and searchInNames:
                if bookmark["name"].find(value) >= 0 or \
                   (ignoreCase and bookmark["name"].lower().find(value.lower()) >= 0):
                    valid = True

            if not valid and searchInTags:
                if bookmark["tag"].find(value) >= 0 or \
                   (ignoreCase and bookmark["tag"].lower().find(value.lower()) >= 0):
                    valid = True

            if not valid and searchInDescriptions:
                if bookmark["description"].find(value) >= 0 or \
                   (ignoreCase and bookmark["description"].lower().find(value.lower()) >= 0):
                    valid = True

            entry = url
            if self.display == "bkm_choose_name":
                entry = bookmark["name"]

            if valid:
                if not entry in self.filter:
                    self.filter.append(entry)
                    self.addValue("bkm_list", entry)
            else:
                if entry in self.filter:
                    self.removeValue("bkm_list", entry)
                    self.filter.remove(entry)

    ## at least: notification by scale, entry or menu
    def updateValue(self, wid, value, mode):
        #print "BookmarksModel: wid: %(wid)s = %(value)s (has been changed)" % (locals())

        # traing to add a new bookmark
        if wid == "bkm_add":
            self.addBookmark()
        # clearing the input for defining a new bookmark
        elif wid == "bkm_new":
            self.newBookmark()
        # changing currently selected bookmark
        elif wid == "bkm_change":
            self.changeBookmark()
        # deleting currently selected bookmark
        elif wid == "bkm_delete":
            self.deleteBookmark()
        # search input has changed - adjusting the filter
        elif wid == "bkm_search":
            self.searchBookmark(value)
            # displaying details for first (selected) row...
            self.select("bkm_list", 0)
            value = self.getValue("bkm_list", 0)
            self.updateValue("bkm_list", value, "changed")

        # saving bookmarks and options
        elif wid == "bkm_file_save":
            self.save()
        # leaving the application
        elif wid == "bkm_file_quit":
            self.quit()

        # toogle between displaying url's or name's.
        elif wid == "bkm_choose_url" or wid == "bkm_choose_name":
            if self.display == wid:
                return

            self.display = wid
            self.rebuildList()

        elif wid == "bkm_list":
            if mode == "changed":
                if not self.hasUrlOrName(value):
                    print self.getText("#bkm_error_missing_url_or_name") % (value)
                else:
                    self.current = self.getUrlOrName(value)
                    self.setValue("bkm_name"       , self.current["name"])
                    self.setValue("bkm_url"        , self.current["url"])
                    self.setValue("bkm_description", self.current["description"])
                    self.setValue("bkm_tag"        , self.current["tag"])

                    text = "created: %s %s     changed: %s %s" % \
                           (self.current["created"][0], self.current["created"][1], \
                            self.current["changed"][0], self.current["changed"][1])

                    self.setValue("bkm_created_changed", text)

                    self.setAttribute("bkm_name"  , "state", "disabled")
                    self.setAttribute("bkm_url"   , "state", "disabled")
                    self.setAttribute("bkm_add"   , "state", "disabled")
                    self.setAttribute("bkm_change", "state", "normal")
                    self.setAttribute("bkm_delete", "state", "normal")

            elif mode == "deleted":
                if self.bookmarks.has_key(value):
                    del self.bookmarks[value]

                if self.getValue("bkm_url") == value:
                    self.newBookmark()

        elif wid == "bkm_name":
            for bookmark in self.bookmarks.values():
                if bookmark["name"] == value:
                    self.setAttribute("bkm_add", "state", "disabled")
                    return

            self.setAttribute("bkm_add", "state", "normal")

        elif wid == "bkm_url":
            if self.bookmarks.has_key(value):
                self.setAttribute("bkm_add", "state", "disabled")
                return

            self.setAttribute("bkm_add", "state", "normal")

    def save(self):
        # saving options from GUI
        self.options["incremental"         ] = self.getValue("bkm_incremental_search")
        self.options["ignorecase"          ] = self.getValue("bkm_ignorecase")
        self.options["search_names"        ] = self.getValue("bkm_search_names")
        self.options["search_urls"         ] = self.getValue("bkm_search_urls")
        self.options["search_tags"         ] = self.getValue("bkm_search_tags")
        self.options["search_descriptions" ] = self.getValue("bkm_search_descriptions")
        self.options["search"              ] = self.getValue("bkm_search")
        self.options["display"             ] = self.display
        self.options["backup"              ] = self.backup

        # saving all bookmarks and all options
        pickle.dump(self.data, gzip.open("bookmarks.gz", "w"))

    def event(self, wid, evid):
        if wid == "bkm_list" and evid == "bkm_double_click":
            webbrowser.open_new_tab(self.getValue("bkm_url"))

def createModel():
    return BookmarksModel()

